/*
 * Copyright (C) 2011 by Fabien Barbero
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.flickr.api.photos;

import com.flickr.api.AbstractFlickrService;
import com.flickr.api.ApiKey;
import com.flickr.api.CommandArguments;
import com.flickr.api.VoidResponse;
import com.flickr.api.FlickrServiceException;
import com.flickr.api.Paginated;
import com.flickr.api.LocalCache;
import com.flickr.api.people.User;
import com.flickr.api.auth.AuthenticationService;
import com.google.inject.Inject;
import java.util.List;

/**
 *
 * @author Fabien Barbero
 */
public class PhotosServiceImpl extends AbstractFlickrService implements PhotosService {

    private final ApiKey apiKey;
    private final AuthenticationService authService;
    private final LocalCache cache;

    @Inject
    public PhotosServiceImpl(ApiKey apiKey, AuthenticationService authService, LocalCache cache) {
        this.apiKey = apiKey;
        this.authService = authService;
        this.cache = cache;
    }

    @Override
    public void addTags(Photo photo, String... tags) throws FlickrServiceException {
        CommandArguments args = new CommandArguments("flickr.photos.addTags", apiKey);
        args.put("photo_id", photo.getId());
        args.put("tags", convertTags(tags));
        doPost(args, VoidResponse.class);
    }

    @Override
    public void removeTag(Photo photo, PhotoTag tag) throws FlickrServiceException {
        CommandArguments args = new CommandArguments("flickr.photos.removeTag", apiKey);
        args.put("tag_id", tag.getId());
        doPost(args, VoidResponse.class);
    }

    @Override
    public void delete(Photo photo) throws FlickrServiceException {
        CommandArguments args = new CommandArguments("flickr.photos.delete", apiKey);
        doPost(args, VoidResponse.class);
    }

    @Override
    public List<Photo> getContactsPhotos() throws FlickrServiceException {
        CommandArguments args = new CommandArguments("flickr.photos.getContactsPhotos", apiKey);
        List<Photo> photos = doGet(args, PhotosResponse.class).getPhotos();
        addCacheToPhotos(photos);
        return photos;
    }

    @Override
    public List<Photo> getContactsPhotos(int count, boolean justFriends, boolean singlePhoto, boolean includeSelf) throws FlickrServiceException {
        CommandArguments args = new CommandArguments("flickr.photos.getContactsPhotos", apiKey);
        args.put("count", count);
        args.put("just_friends", justFriends);
        args.put("single_photo", singlePhoto);
        args.put("include_self", includeSelf);
        List<Photo> photos = doGet(args, PhotosResponse.class).getPhotos();
        addCacheToPhotos(photos);
        return photos;
    }

    @Override
    public List<Photo> getContactsPublicPhotos(User user) throws FlickrServiceException {
        CommandArguments args = new CommandArguments("flickr.photos.getContactsPublicPhotos", apiKey);
        args.put("user_id", user.getId());
        List<Photo> photos = doGet(args, PhotosResponse.class).getPhotos();
        addCacheToPhotos(photos);
        return photos;
    }

    @Override
    public List<Photo> getContactsPublicPhotos(User user, int count, boolean justFriends, boolean singlePhoto, boolean includeSelf) throws FlickrServiceException {
        CommandArguments args = new CommandArguments("flickr.photos.getContactsPublicPhotos", apiKey);
        args.put("user_id", user.getId());
        args.put("count", count);
        args.put("just_friends", justFriends);
        args.put("single_photo", singlePhoto);
        args.put("include_self", includeSelf);
        List<Photo> photos = doGet(args, PhotosResponse.class).getPhotos();
        addCacheToPhotos(photos);
        return photos;
    }

    @Override
    public PhotoContext getContext(Photo photo) throws FlickrServiceException {
        CommandArguments args = new CommandArguments("flickr.photos.getContext", apiKey);
        args.put("photo_id", photo.getId());
        return doGet(args, PhotoContext.class);
    }

    @Override
    public List<Exif> getExif(Photo photo) throws FlickrServiceException {
        CommandArguments args = new CommandArguments("flickr.photos.getExif", apiKey);
        args.put("photo_id", photo.getId());
        return doGet(args, ExifsResponse.class).getExifs();
    }

    @Override
    public List<Person> getFavorites(Photo photo) throws FlickrServiceException {
        CommandArguments args = new CommandArguments("flickr.photos.getFavorites", apiKey);
        args.put("photo_id", photo.getId());
        return doGet(args, PersonsResponse.class).getPersons();
    }

    @Override
    public PhotoInfos getInfos(Photo photo) throws FlickrServiceException {
        CommandArguments args = new CommandArguments("flickr.photos.getInfo", apiKey);
        args.put("photo_id", photo.getId());
        return doGet(args, PhotoInfosResponse.class).getInfos();
    }

    @Override
    public Paginated<Photo> getNotInSet(int perPage, int page) throws FlickrServiceException {
        CommandArguments args = new CommandArguments("flickr.photos.getNotInSet", apiKey);
        args.put("per_page", perPage);
        args.put("page", page);
        Paginated<Photo> photos = doGet(args, PaginatedPhotosResponse.class).getPhotos();
        addCacheToPhotos(photos);
        return photos;
    }

    @Override
    public PhotoAccess getPermission(Photo photo) throws FlickrServiceException {
        CommandArguments args = new CommandArguments("flickr.photos.getPerms", apiKey);
        return doGet(args, PhotoAccess.class);
    }

    @Override
    public Paginated<Photo> getRecent(int perPage, int page) throws FlickrServiceException {
        CommandArguments args = new CommandArguments("flickr.photos.getRecent", apiKey);
        args.put("per_page", perPage);
        args.put("page", page);
        Paginated<Photo> photos = doGet(args, PaginatedPhotosResponse.class).getPhotos();
        addCacheToPhotos(photos);
        return photos;
    }

    @Override
    public List<PhotoSize> getSizes(Photo photo) throws FlickrServiceException {
        CommandArguments args = new CommandArguments("flickr.photos.getSizes", apiKey);
        args.put("photo_id", photo.getId());
        List<PhotoSize> sizes = doGet(args, PhotoSizesResponse.class).getSizes();
        addCacheToSizes(sizes);
        return sizes;
    }
    
    @Override
    public Paginated<Photo> getRecentlyUpdated(int perPage, int page) throws FlickrServiceException {
        CommandArguments args = new CommandArguments("flickr.photos.recentlyUpdated", apiKey);
        args.put("per_page", perPage);
        args.put("page", page);
        Paginated<Photo> photos = doGet(args, PaginatedPhotosResponse.class).getPhotos();
        addCacheToPhotos(photos);
        return photos;
    }

    @Override
    public void setMeta(Photo photo, String title, String description) throws FlickrServiceException {
        CommandArguments args = new CommandArguments("flickr.photos.setMeta", apiKey);
        args.put("photo_id", photo.getId());
        args.put("title", title);
        args.put("description", description);
        doPost(args, VoidResponse.class);
    }

    @Override
    public void setPerms(Photo photo, boolean ispublic, boolean isfriend, boolean isfamily, CommentPermission commentPerm, AddMetaPermission addMetaPerm) throws FlickrServiceException {
        CommandArguments args = new CommandArguments("flickr.photos.setPerms", apiKey);
        args.put("photo_id", photo.getId());
        args.put("is_public", ispublic);
        args.put("is_friend", isfriend);
        args.put("is_family", isfamily);
        args.put("perm_comment", commentPerm.getValue());
        args.put("perm_addmeta", addMetaPerm.getValue());
        doPost(args, VoidResponse.class);
    }

    @Override
    public void setTags(Photo photo, String... tags) throws FlickrServiceException {
        CommandArguments args = new CommandArguments("flickr.photos.setTags", apiKey);
        args.put("photo_id", photo.getId());
        args.put("tags", convertTags(tags));
        doPost(args, VoidResponse.class);
    }

    private String convertTags(String... tags) {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < tags.length; i++) {
            builder.append(tags[i]);
            if (i < tags.length) {
                builder.append(" ");
            }
        }
        return builder.toString();
    }

    @Override
    public void setSafetyLevel(Photo photo, PhotoSafetyLevel level, boolean hidden) throws FlickrServiceException {
        CommandArguments args = new CommandArguments("flickr.photos.setSafetyLevel", apiKey);
        args.put("photo_id", photo.getId());
        args.put("safety_level", level.getValue());
        args.put("hidden", hidden);
        doPost(args, VoidResponse.class);
    }
    
    private void addCacheToSizes(List<PhotoSize> sizes) {
        for(PhotoSize size : sizes) {
            size.setCache(cache);
        }
    }
    
    private void addCacheToPhotos(Paginated<Photo> photos) {
        for(Photo photo : photos.getValues()) {
            photo.setCache(cache);
        }
    }
    
    private void addCacheToPhotos(List<Photo> photos) {
        for(Photo photo : photos) {
            photo.setCache(cache);
        }
    }
}
